#include "CryptoMetadata.h"
#include "SymmetricEncrypter.h"
#include <string.h>

namespace kryptos { namespace cryptography {

CryptoMetadata::CryptoMetadata()
{
    m_symkeys.clear();
    m_metadataBytes.clear();
    m_metadataBytesCurrentIndex = 0;
}

CryptoMetadata::CryptoMetadata(const char* buffer, int len)
{
    m_symkeys.clear();
    m_metadataBytes.clear();
    m_metadataBytes.resize(len);
    m_metadataBytes.assign(buffer, buffer + len);

    m_metadataBytesCurrentIndex = m_metadataBytes.size();
}

CryptoMetadata::~CryptoMetadata()
{
    m_symkeys.clear();
    m_metadataBytes.clear();
}

void CryptoMetadata::addSymmetricKeyInfo(const std::string& keyid, unsigned long long offset)
{
    /**
     * Metadata structure:
     *        - key id            [20 bytes]
     *        - offset            [sizeof(unsigned long long) ~ 8bytes
     **/
    m_metadataBytes.resize(m_metadataBytes.size() + 20 + sizeof(unsigned long long));

    std::copy(keyid.begin(), keyid.begin()+20, &m_metadataBytes[m_metadataBytesCurrentIndex]);
    memcpy(&m_metadataBytes[m_metadataBytesCurrentIndex+20], (char*)&offset, sizeof(unsigned long long));

    m_metadataBytesCurrentIndex += m_metadataBytes.size();
}

std::vector<char> CryptoMetadata::encrypt(SymmetricKey& sessionKey)
{
    SymmetricEncrypter encrypter(sessionKey);
    encrypter.encryptBuffer((const char*)&m_metadataBytes[0], m_metadataBytes.size(), m_metadataBytes);

    return m_metadataBytes;
}

std::vector<char> CryptoMetadata::decrypt(SymmetricKey& sessionKey)
{
    SymmetricEncrypter decrypter(sessionKey);
    decrypter.decryptBuffer((const char*)&m_metadataBytes[0], m_metadataBytes.size(), m_metadataBytes);

    return m_metadataBytes;
}

std::vector<char> CryptoMetadata::bytes()
{
    return m_metadataBytes;
}

std::vector<std::pair<std::string, unsigned long long> > CryptoMetadata::keys()
{
    unsigned long long offset;
    std::string idstr;
    idstr.resize(20);

    int index = 0;
    while (index < m_metadataBytes.size())
    {
        idstr.assign(m_metadataBytes.begin() + index, m_metadataBytes.begin() + index + 20);
        std::copy(m_metadataBytes.begin() + index + 20, m_metadataBytes.begin() + index + 20 + sizeof(unsigned long long), &offset);

        m_symkeys.push_back(std::make_pair(idstr, offset));

        index += 20 + sizeof(unsigned long long);
    }

    return m_symkeys;
}

}}
